/*
* Copyright (c) 2021.04
* All rights reserved.
*
* 文件节点：xmlhelper.h
*
* 初始版本：1.0
* 作者：shelman
* 创建日期：2021年4月28日
* 摘要：对tinyxml类进行了封装的xml处理帮助类
*
*/

#ifndef XMLHELPER_H
#define XMLHELPER_H


#include <string>
#include <list>
#include <vector>
#include <memory>


#if defined(_WIN32) || defined(_WIN64)
#define XmlHelper_DllExport __declspec(dllexport)
#else
#define XmlHelper_DllExport __attribute__((visibility("default")))
#endif  // _WIN32


namespace tinyxml2
{
class XMLDocument;
class XMLElement;
}

class XmlHelper_DllExport XmlHelper
{
public:
    /************************************************
     * 功能：构造函数
     * ***********************************************/
    XmlHelper();

    /************************************************
     * 功能：析构函数
     * ***********************************************/
    ~XmlHelper();

    /************************************************
     * 功能：重置和清空xml内容
     * ***********************************************/
    void clear();

    /************************************************
     * 功能：保存xml文件
     * 返回值：
     *      bool：操作结果，true -- 成功，false -- 失败
     * ***********************************************/
    bool saveXmlFile();

    /************************************************
     * 功能：解析xml文件
     * 注：自动进入root节点
     * 输入参数：
     *      strXmlContent：xml内容
     * 返回值：
     *      bool：操作结果，true -- 成功，false -- 失败
     * ***********************************************/
    bool parseXmlContent(const std::string &strXmlContent);

    /************************************************
     * 功能：获取xml文件中的xml内容
     * 输入参数：
     *      strXmlFilePath：xml文件路径
     * 返回值：
     *      std::string：xml内容
     * ***********************************************/
    std::string getXmlFileContent(const std::string &strXmlFilePath);

    /************************************************
     * 功能：获取当前DOC中的xml内容
     * 返回值：
     *      std::string：xml内容
     * ***********************************************/
    std::string getXmlContent();

    /************************************************
     * 功能：创建xml文件
     * 注：自动进入root节点
     * 输入参数：
     *      strXmlFilePath：xml文件路径
     *      strRootName：根节点名称
     * 返回值：
     *      bool：操作结果，true -- 成功，false -- 失败
     * ***********************************************/
    bool createXmlFilePath(const std::string &strXmlFilePath, const std::string &strRootName);

    /************************************************
     * 功能：加载并读入xml文件
     * 注：自动进入root节点
     * 输入参数：
     *      strXmlFilePath：xml文件路径
     * 返回值：
     *      bool：操作结果，true -- 成功，false -- 失败
     * ***********************************************/
    bool loadXmlFile(const std::string &strXmlFilePath);

    /************************************************
     * 功能：定位到根节点位置
     * ***********************************************/
    void beginRootElement();

    /************************************************
     * 功能：获取当前节点的名称标识
     * 返回值：
     *		std::string：当前节点名称标识
     * ***********************************************/
    std::string currentElemName();

    /************************************************
     * 功能：获取当前节点的内容值
     * 返回值：
     *      std::string：当前节点内容值
     * ***********************************************/
    std::string currentElemText();

    /************************************************
     * 功能：判断当前节点中是否存在指定名称的子节点
     * 输入参数：
     *      strName：子节点的名称标识
     * 返回值：
     *      bool：判断结果，true -- 存在，false -- 不存在
     * ***********************************************/
    bool hasChildElement(const std::string &strName);

    /************************************************
     * 功能：当前节点中定位到指定名称的子节点
     * 输入参数：
     *      strName：子节点的名称标识
     * ***********************************************/
    void beginChildElement(const std::string &strName);

    /************************************************
     * 功能：当前节点中定位到指定子节点
     * 输入参数：
     *      pElement：子节点的指针
     * ***********************************************/
    void beginElement(tinyxml2::XMLElement *pElement);

    /************************************************
     * 功能：结束当前节点到其父节点位置
     * ***********************************************/
    void endElement();

    /************************************************
     * 功能：从当前节点中添加指定名称的子节点
     * 输入参数：
     *      strName：子节点的名称标识
     * 返回值：
     *      tinyxml2::XMLElement*：子节点的指针
     * ***********************************************/
    tinyxml2::XMLElement* addChildElement(const std::string &strName);

    /************************************************
     * 功能：从当前节点中删除所有指定名称的子节点
     * 输入参数：
     *      strName：子节点的名称标识
     * ***********************************************/
    void deleteChildElement(const std::string &strName);

    /************************************************
     * 功能：获取当前节点中所有指定名称的子节点，一般用于操作xml中的list节点
     * 输入参数：
     *      strName：子节点的名称标识
     * 返回值：
     *      std::list<tinyxml2::XMLElement *>：子节点集合
     * ***********************************************/
    std::list<tinyxml2::XMLElement *> childElements(const std::string &strName);

    /************************************************
     * 功能：获取当前节点中所有指定名称的子节点，一般用于操作xml中的list节点
     * 输入参数：
     *      strName：子节点的名称标识
     * 输出参数：
     *      lstElements：子节点集合
     * ***********************************************/
    void childElements(const std::string &strName, std::list<tinyxml2::XMLElement *> lstElements);

    /************************************************
     * 功能：获取当前节点中所有指定名称的子节点，一般用于操作xml中的list节点
     * 输入参数：
     *      strName：子节点的名称标识
     * 输出参数：
     *      vtElements：子节点集合
     * ***********************************************/
    void childElements(const std::string &strName, std::vector<tinyxml2::XMLElement *> vtElements);

    /************************************************
     * 功能：设置当前节点的内容值，字符串类型数据
     * 输入参数：
     *      pText：节点的内容值
     * ***********************************************/
    void setText(const char *pText);

    /************************************************
     * 功能：设置当前节点的内容值，字符串类型数据
     * 输入参数：
     *      strText：节点的内容值
     * ***********************************************/
    void setText(const std::string &strText);

    /************************************************
     * 功能：设置当前节点的内容值，int类型数据
     * 输入参数：
     *      iText：节点的内容值
     * ***********************************************/
    void setText(int iText);

    /************************************************
     * 功能：设置当前节点的内容值，double类型数据
     * 输入参数：
     *      dText：节点的内容值
     * ***********************************************/
    void setText(double dText);

    /************************************************
     * 功能：设置当前节点的内容值，bool类型数据
     * 输入参数：
     *      bText：子节点的内容值
     * ***********************************************/
    void setText(bool bText);

    /************************************************
     * 功能：设置当前节点中指定名称子节点的内容值，字符串类型数据
     * 注：最后一个子节点名不匹配时，创建/追加子节点
     * 输入参数：
     *      strName：子节点的名称标识
     *      pText：子节点的内容值
     * ***********************************************/
    void setChildText(const std::string &strName, const char *pText);

    /************************************************
     * 功能：设置当前节点中指定名称子节点的内容值，字符串类型数据
     * 注：最后一个子节点名不匹配时，创建/追加子节点
     * 输入参数：
     *      strName：子节点的名称标识
     *      strText：子节点的内容值
     * ***********************************************/
    void setChildText(const std::string &strName, const std::string &strText);

    /************************************************
     * 功能：设置当前节点中指定名称子节点的内容值，int类型数据
     * 注：最后一个子节点名不匹配时，创建/追加子节点
     * 输入参数：
     *      strName：子节点的名称标识
     *      iText：子节点的内容值
     * ***********************************************/
    void setChildText(const std::string &strName, int iText);

    /************************************************
     * 功能：设置当前节点中指定名称子节点的内容值，double类型数据
     * 注：最后一个子节点名不匹配时，创建/追加子节点
     * 输入参数：
     *      strName：子节点的名称标识
     *      dText：子节点的内容值
     * ***********************************************/
    void setChildText(const std::string &strName, double dText);

    /************************************************
     * 功能：设置当前节点中指定名称子节点的内容值，bool类型数据
     * 注：最后一个子节点名不匹配时，创建/追加子节点
     * 输入参数：
     *      strName：子节点的名称标识
     *      bText：子节点的内容值
     * ***********************************************/
    void setChildText(const std::string &strName, bool bText);

    /************************************************
     * 功能：获取当前节点的内容值，字符串类型数据
     * 返回值：
     *      std::string：节点的内容值
     * ***********************************************/
    std::string text();

    /************************************************
     * 功能：获取当前节点的内容值，int类型数据
     * 返回值：
     *      int：节点的内容值
     * ***********************************************/
    int intText();

    /************************************************
     * 功能：获取当前节点的内容值，double类型数据
     * 返回值：
     *      double：节点的内容值
     * ***********************************************/
    double doubleText();

    /************************************************
     * 功能：获取当前节点的内容值，bool类型数据
     * 返回值：
     *      bool：节点的内容值
     * ***********************************************/
    bool boolText();

    /************************************************
     * 功能：获取当前节点中指定名称子节点的内容值，字符串类型数据
     * 输入参数：
     *      strName：子节点的名称标识
     * 返回值：
     *      std::string：子节点的内容值
     * ***********************************************/
    std::string childText(const std::string &strName);

    /************************************************
     * 功能：获取当前节点中指定名称子节点的内容值，int类型数据
     * 输入参数：
     *      strName：子节点的名称标识
     * 返回值：
     *      int：子节点的内容值
     * ***********************************************/
    int childIntText(const std::string &strName);

    /************************************************
     * 功能：获取当前节点中指定名称子节点的内容值，double类型数据
     * 输入参数：
     *      strName：子节点的名称标识
     * 返回值：
     *      double：子节点的内容值
     * ***********************************************/
    double childDoubleText(const std::string &strName);

    /************************************************
     * 功能：获取当前节点中指定名称子节点的内容值，bool类型数据
     * 输入参数：
     *      strName：子节点的名称标识
     * 返回值：
     *      bool：子节点的内容值
     * ***********************************************/
    bool childBoolText(const std::string &strName);

    /************************************************
     * 功能：为当前节点设置指定属性的值，字符串类型数据
     * 输入参数：
     *      strAttributeName：当前节点的指定属性名称标识
     *      pValue：当前节点的指定属性的值
     * ***********************************************/
    void setAttribute(const std::string &strAttributeName, const char *pValue);

    /************************************************
     * 功能：为当前节点设置指定属性的值，字符串类型数据
     * 输入参数：
     *      strAttributeName：当前节点的指定属性名称标识
     *      strValue：当前节点的指定属性的值
     * ***********************************************/
    void setAttribute(const std::string &strAttributeName, const std::string &strValue);

    /************************************************
     * 功能：为当前节点设置指定属性的值，int类型数据
     * 输入参数：
     *      strAttributeName：当前节点的指定属性名称标识
     *      iValue：当前节点的指定属性的值
     * ***********************************************/
    void setAttribute(const std::string &strAttributeName, int iValue);

    /************************************************
     * 功能：为当前节点设置指定属性的值，double类型数据
     * 输入参数：
     *      strAttributeName：当前节点的指定属性名称标识
     *      dValue：当前节点的指定属性的值
     * ***********************************************/
    void setAttribute(const std::string &strAttributeName, double dValue);

    /************************************************
     * 功能：为当前节点设置指定属性的值，bool类型数据
     * 输入参数：
     *      strAttributeName：当前节点的指定属性名称标识
     *      bValue：当前节点的指定属性的值
     * ***********************************************/
    void setAttribute(const std::string &strAttributeName, bool bValue);

    /************************************************
     * 功能：设置当前节点中指定名称子节点指定属性的值，字符串类型数据
     * 注：最后一个子节点名不匹配时，创建/追加子节点
     * 输入参数：
     *      strName：子节点的名称标识
     *      strAttributeName：子节点的指定属性名称标识
     *      pVal：子节点的指定属性的值
     * ***********************************************/
    void setChildAttribute(const std::string &strName, const std::string &strAttributeName, const char *pVal);

    /************************************************
     * 功能：设置当前节点中指定名称子节点指定属性的值，字符串类型数据
     * 注：最后一个子节点名不匹配时，创建/追加子节点
     * 输入参数：
     *      strName：子节点的名称标识
     *      strAttributeName：子节点的指定属性名称标识
     *      strValue：子节点的指定属性的值
     * ***********************************************/
    void setChildAttribute(const std::string &strName, const std::string &strAttributeName, const std::string &strValue);

    /************************************************
     * 功能：设置当前节点中指定名称子节点指定属性的值，int类型数据
     * 注：最后一个子节点名不匹配时，创建/追加子节点
     * 输入参数：
     *      strName：子节点的名称标识
     *      strAttributeName：子节点的指定属性名称标识
     *      iValue：子节点的指定属性的值
     * ***********************************************/
    void setChildAttribute(const std::string &strName, const std::string &strAttributeName, int iValue);

    /************************************************
     * 功能：设置当前节点中指定名称子节点指定属性的值，double类型数据
     * 注：最后一个子节点名不匹配时，创建/追加子节点
     * 输入参数：
     *      strName：子节点的名称标识
     *      strAttributeName：子节点的指定属性名称标识
     *      dValue：子节点的指定属性的值
     * ***********************************************/
    void setChildAttribute(const std::string &strName, const std::string &strAttributeName, double dValue);

    /************************************************
     * 功能：设置当前节点中指定名称子节点指定属性的值，bool类型数据
     * 注：最后一个子节点名不匹配时，创建/追加子节点
     * 输入参数：
     *      strName：子节点的名称标识
     *      strAttributeName：子节点的指定属性名称标识
     *      bValue：子节点的指定属性的值
     * ***********************************************/
    void setChildAttribute(const std::string &strName, const std::string &strAttributeName, bool bValue);

    /************************************************
     * 功能：删除当前节点中指定属性标识
     * 输入参数：
     *      strAttributeName：当前节点的指定属性名称标识
     * ***********************************************/
    void deleteAttribute(const std::string &strAttributeName);

    /************************************************
     * 功能：删除当前节点中指定名称子节点指定属性标识
     * 输入参数：
     *      strName：子节点的名称标识
     *      strAttributeName：子节点的指定属性名称标识
     * ***********************************************/
    void deleteChildAttribute(const std::string &strName, const std::string &strAttributeName);

    /************************************************
     * 功能：获取当前节点中指定属性标识的值，字符串类型
     * 返回值：
     *      std::string：当前节点的指定属性的字符串值
     * ***********************************************/
    std::string attribute(const std::string &strAttributeName);

    /************************************************
     * 功能：获取当前节点中指定属性标识的值，int类型
     * 输入参数：
     *      strAttributeName：当前节点的指定属性名称标识
     * 返回值：
     *      int：当前节点的指定属性的int值
     * ***********************************************/
    int intAttribute(const std::string &strAttributeName);

    /************************************************
     * 功能：获取当前节点中指定属性标识的值，double类型
     * 输入参数：
     *      strAttributeName：当前节点的指定属性名称标识
     * 返回值：
     *      double：当前节点的指定属性的double值
     * ***********************************************/
    double doubleAttribute(const std::string &strAttributeName);

    /************************************************
     * 功能：获取当前节点中指定属性标识的值，bool类型
     * 输入参数：
     *      strAttributeName：当前节点的指定属性名称标识
     * 返回值：
     *      bool：当前节点的指定属性的bool值
     * ***********************************************/
    bool boolAttribute(const std::string &strAttributeName);

    /************************************************
     * 功能：获取当前节点中指定名称子节点指定属性标识的值，字符串类型
     * 输入参数：
     *      strName：子节点的名称标识
     *      strAttributeName：子节点的指定属性名称标识
     * 返回值：
     *      std::string：子节点的指定属性的字符串值
     * ***********************************************/
    std::string childAttribute(const std::string &strName, const std::string &strAttributeName);

    /************************************************
     * 功能：获取当前节点中指定名称子节点指定属性标识的值，int类型
     * 输入参数：
     *      strName：子节点的名称标识
     *      strAttributeName：子节点的指定属性名称标识
     * 返回值：
     *      int：子节点的指定属性的int值
     * ***********************************************/
    int childIntAttribute(const std::string &strName, const std::string &strAttributeName);

    /************************************************
     * 功能：获取当前节点中指定名称子节点指定属性标识的值，double类型
     * 输入参数：
     *      strName：子节点的名称标识
     *      strAttributeName：子节点的指定属性名称标识
     * 返回值：
     *      double：子节点的指定属性的double值
     * ***********************************************/
    double childDoubleAttribute(const std::string &strName, const std::string &strAttributeName);

    /************************************************
     * 功能：获取当前节点中指定名称子节点指定属性标识的值，bool类型
     * 输入参数：
     *      strName：子节点的名称标识
     *      strAttributeName：子节点的指定属性名称标识
     * 返回值：
     *      bool：子节点的指定属性的bool值
     * ***********************************************/
    bool childBoolAttribute(const std::string &strName, const std::string &strAttributeName);

private:
    std::string m_strXmlFilePath = ""; // xml文件路径
    std::shared_ptr<tinyxml2::XMLDocument> m_spDoc = nullptr; // xml文件的DOC
    tinyxml2::XMLElement *m_pCurElement = nullptr; // xml文件中的当前操作节点指针
};

#endif // XMLHELPER_H
